﻿/*
 * Released under Microsoft Public License (Ms-PL) 
 * Sponsored by Development Platform Evangelism unit of Microsoft Israel
 * 
 * Copyright © 2008 by Tamir Khason
 * http://blogs.microsoft.co.il/blogs/tamir/
 * http://sharpsoft.net/
 * 
 * More information including licensing and term of use
 * can be found on http://www.codeplex.com/SilverlightRTL/
 * 
 */

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Browser;

namespace System.Windows.BidiControls
{
    /// <summary>
    /// Represents base class for UI elements that support bidirectional input and output
    /// </summary>
    [TemplateVisualState(Name = "RightToLeft", GroupName = "FlowDirection")]
    [TemplateVisualState(Name = "LeftToRight", GroupName = "FlowDirection")]
    public abstract class Control : System.Windows.Controls.Control
    {
        #region FlowDirection
        protected bool fdWasSet = false;
        /// <summary> 
        /// Gets or sets the FlowDirection possible Value of the FlowDirection object.
        /// </summary> 
        public FlowDirection FlowDirection
        {
            get { return (FlowDirection)GetValue(FlowDirectionProperty); }
            set { SetValue(FlowDirectionProperty, value); }
        }

        /// <summary> 
        /// Identifies the FlowDirection dependency property.
        /// </summary> 
        public static readonly DependencyProperty FlowDirectionProperty =
                    DependencyProperty.Register(
                          "FlowDirection",
                          typeof(FlowDirection),
                          typeof(Control),
                          new PropertyMetadata(FlowDirection.RightToLeft, new PropertyChangedCallback(OnFlowDirectionPropertyChangedIml)));

        /// <summary>
        /// FlowDirectionProperty property changed handler. 
        /// </summary>
        /// <param name="d">Control that changed its FlowDirection.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
        internal static void OnFlowDirectionPropertyChangedIml(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Control _ctl = d as Control;
            if (_ctl != null)
            {
                _ctl.fdWasSet = true;
                _ctl.OnFlowDirectionPropertyChanged(d, e);
                if (((FlowDirection)e.NewValue) == FlowDirection.LeftToRight)
                    VisualStateManager.GoToState(_ctl, "LeftToRight", true);
                else
                    VisualStateManager.GoToState(_ctl, "RightToLeft", true);
            }
        }

        /// <summary>
        /// FlowDirectionProperty property changed handler. 
        /// </summary>
        /// <param name="d">Control that changed its FlowDirection.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param> 
        protected virtual void OnFlowDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
        #endregion FlowDirection
       
        public Control()
        {
            base.KeyDown += onInternalKeyDown;
            base.KeyUp += onInternalKeyUp;

            if (HtmlPage.IsEnabled && !fdWasSet && !String.IsNullOrEmpty(HtmlPage.Document.Body.GetAttribute("dir")))
            {
                string dir = HtmlPage.Document.Body.GetAttribute("dir");
                FlowDirection = dir.ToLower() == "rtl" ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
            }
        }

        void onInternalKeyUp(object sender, KeyEventArgs e)
        {
            
            //no LShift/RShift - just switch
            //also no such switch in Mac (Alt-[ ]?)
            if (isCtrl && e.Key == Key.Shift)
            {
                this.FlowDirection = (this.FlowDirection == FlowDirection.LeftToRight) ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
            }
            if (isCtrl)
            {
                isCtrl = !(e.Key == Key.Ctrl);
            }
        }

        void onInternalKeyDown(object sender, KeyEventArgs e)
        {
            if (!isCtrl)
            {
                isCtrl = e.Key == Key.Ctrl;
            }
        }

        bool isCtrl = false;
    }

    /// <summary>
    /// Represents enumirator for setting text input and output direction
    /// </summary>
    public enum FlowDirection
    {
        LeftToRight,
        RightToLeft
    }

    /// <summary>
    /// Converts FlowDirection enum to Boolean value and Boolean value to FlowDirection while 
    /// FlowDirection.RightToLeft equals to true and FlowDirection.LeftToRight to false
    /// </summary>
    public class BooleandToFlowDirectionConverter : IValueConverter
    {
        #region IValueConverter Members
        /// <summary>
        /// Converts FlowDirection enum to Boolean value
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is FlowDirection && targetType.IsAssignableFrom(typeof(Boolean)))
            {
                return ((FlowDirection)value) == FlowDirection.RightToLeft ? true : false;
            }
            return DependencyProperty.UnsetValue;
        }

        /// <summary>
        /// Converts Boolean value to FlowDirection enum
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is bool && targetType.IsAssignableFrom(typeof(FlowDirection)))
            {
                return ((bool)value) ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
            }
            return DependencyProperty.UnsetValue;
        }

        #endregion
    }


}
